/* CS45 Lab 1 Ben Marks, Cal Smith
 *
 * Implementation of the history buffer and related
 * procedures.
 */

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include"parsecmd.h" /* for Malloc */
#include"history.h"

/* Procedure to determine if the input string is a command
 * for the history subsystem.
 *
 * Input c is the string being checked.
 *
 * Returns 0 if c is not related to history.
 *         2 if c is a command to display the history.
 *         1 if c is a command to access part of the history.
 */
int is_history_command(char *c)
{
  if(!strcmp("history", c))
    return 2;
  else if(*c == '!')
    return 1;
  else
    return 0;
}

/* Procedure to display the contents of a history struct.
 *
 * Input h is a pointer to the history struct to be displayed.
 */
void display_history(history *h)
{
  int i;

  printf("Number\t\tCommand\n");

  /* Displays the most recent history item first. */
  for(i = h->newest; i; i--)
    if(h->hist[i].cmd)
      printf("%d\t\t%s\n", h->hist[i].num, h->hist[i].cmd);
  for(i = HISTSIZE - 1; i > h->newest; i--)
    if(h->hist[i].cmd)
      printf("%d\t\t%s\n", h->hist[i].num, h->hist[i].cmd);
}

/* Procedure to add a new command line to the history.
 *
 * Input h is a pointer to the history buffer.
 *       cl is a string holding the command line to add to
 *          the buffer.
 */
void add_to_history(history *h, char *cl)
{
  h->newest += 1;
  h->newest %= HISTSIZE;
  h->hist[h->newest].num = ++(h->num);

  /* If the pointer held by the entry struct is not null, it
   * is pointing to a string on the heap. free this string
   * before overwriting the pointer.
   */
  if(h->hist[h->newest].cmd)
    free(h->hist[h->newest].cmd);

  h->hist[h->newest].cmd = Malloc(sizeof(char) * (strlen(cl) + 1));
  strncpy(h->hist[h->newest].cmd, cl, strlen(cl) + 1);
}

/* Procedure that returns a copy of a command line entry from
 * a history buffer.
 *
 * Input h is a pointer to the history buffer being searched.
 *       cl is a string holding a history lookup command.
 *
 * Returns a pointer to a dynamically allocated copy of the string
 * searched for, or NULL if there is no such entry. This
 * procedure does not modify the history buffer.
 */
char * get_history(history *h, char *cl)
{
  char *ret;
  int i, n, entry;

  entry = -1;
  ret = NULL;

  if(*(cl + 1) == '!' && h->newest != 0)
    entry = h->newest;
  else if((n = atoi(cl + 1)) <= h->num && n != 0)
    for(i = 0; i < HISTSIZE; i++)
      if(h->hist[i].num == n){
        entry = i;
        break;
      }
    
  /* If an entry has been found */
  if(entry > -1){
    ret = Malloc(sizeof(char) * (strlen(h->hist[entry].cmd) + 1));
    strncpy(ret, h->hist[entry].cmd, strlen(h->hist[entry].cmd) + 1);
  }

  return ret;
}

/* Procedure to free all dynamically allocated memory pointed to by
 * a history struct.
 *
 * Input h is a pointer to the struct to be cleaned.
 */
void free_history(history *h)
{
  int i;

  for(i = 0; i < HISTSIZE; i++)
    if(h->hist[i].cmd)
      free(h->hist[i].cmd);
}
